/* Copyright (c) 2009, Enric Rodriguez (enrodri86@gmail.com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 	- Redistributions of source code must retain the above copyright
 * 	notice,	this list of conditions and the following disclaimer.
 * 	- Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * 	- Neither the name of the <ORGANIZATION> nor the names of its
 * 	contributors may be used to endorse or promote products derived from
 * 	this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package es.enrodri86.mmo.auth.shared;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import net.iharder.Base64;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class Captcha {
//Please, do not turn this class serializable, read comments below...

	public static final int TYPE_VISUAL = 1;
	public static final int TYPE_AUDIO = 2;

	private byte[] vcaptcha;
	private byte[] acaptcha;
	private String vcaptchaquestion;
	private String acaptchaquestion;

	//We need these two in order to allow basic abstract implementations
	//of AuthServer to check captcha's responses automatically.
	//So you should not turn this class serializable because you risk sending
	//the answer to the client.
	private String vcaptchasolution;
	private String acaptchasolution;


	public Captcha(byte[] captcha, int type) {
		if(type == TYPE_VISUAL){
			vcaptcha = captcha;
		}else{
			acaptcha = captcha;
		}
	}

	public Captcha() {
		// TODO Auto-generated constructor stub
	}

	public boolean isAudioCaptcha(){
		return (acaptcha==null)?false:true;
	}

	public boolean isVisualCaptcha(){
		return (vcaptcha==null)?false:true;
	}

	public byte[] getVisualCaptcha(){
		return vcaptcha;
	}

	public byte[] getAudioCaptcha(){
		return acaptcha;
	}

	public void setAudioCaptcha(byte[] acaptcha) {
		this.acaptcha = acaptcha;
	}

	public void setVisualCaptcha(byte[] vcaptcha) {
		this.vcaptcha = vcaptcha;
	}

	public String getVisualCaptchaQuestion(){
		return vcaptchaquestion;
	}

	public String getAudioCaptchaQuestion(){
		return acaptchaquestion;
	}

	public String getVisualCaptchaSolution(){
		return vcaptchasolution;
	}

	public String getAudioCaptchaSolution(){
		return acaptchasolution;
	}

	public void setAudioCaptchaQuestion(String acaptcha) {
		this.acaptchaquestion = acaptcha;
	}

	public void setVisualCaptchaQuestion(String vcaptcha) {
		this.vcaptchaquestion = vcaptcha;
	}

	public void setAudioCaptchaSolution(String acaptcha) {
		this.acaptchasolution = acaptcha;
	}

	public void setVisualCaptchaSolution(String vcaptcha) {
		this.vcaptchasolution = vcaptcha;
	}

	public String toXML(){
		StringBuffer sb = new StringBuffer();
		sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
		sb.append("<captcha>\n");
		if(isAudioCaptcha()){
			sb.append("\t<audio>\n");
			sb.append("\t\t<aquestion>");
			sb.append(getAudioCaptchaQuestion());
			sb.append("</aquestion>\n");
			sb.append("\t\t<adata><![CDATA[");
			sb.append(Base64.encodeBytes(getAudioCaptcha()));
			sb.append("]]></adata>\n");
			sb.append("\t</audio>\n");
		}
		if(isVisualCaptcha()){
			sb.append("\t<image>\n");
			sb.append("\t\t<vquestion>");
			sb.append(getVisualCaptchaQuestion());
			sb.append("</vquestion>\n");
			sb.append("\t\t<vdata><![CDATA[");
			sb.append(Base64.encodeBytes(getVisualCaptcha()));
			sb.append("]]></vdata>\n");
			sb.append("\t</image>\n");
		}
		sb.append("</captcha>\n");

		return sb.toString();
	}

	public static Captcha fromXML(InputStream xml) throws ParserConfigurationException, SAXException, IOException{
		SAXParser saxParser =  SAXParserFactory.newInstance().newSAXParser();
        CHandler ch = new CHandler();
		saxParser.parse(xml, ch );
		return ch.getCaptcha();
	}

}

class CHandler extends DefaultHandler{

	private StringBuffer accumulator;
	private Captcha captcha;

	public void endElement(String namespaceURL, String localName, String qname){

		if (qname.equals("aquestion")) {
			String k = new String(accumulator.toString()).trim();
			captcha.setAudioCaptchaQuestion(k);
		}else if(qname.equals("vquestion")){
			String k = new String(accumulator.toString()).trim();
			captcha.setVisualCaptchaQuestion(k);
		}else if(qname.equals("adata")){
			captcha.setAudioCaptcha(Base64.decode(accumulator.toString()));
		}else if(qname.equals("vdata")){
			captcha.setVisualCaptcha(Base64.decode(accumulator.toString()));
		}
	}

	public Captcha getCaptcha() {
		return captcha;
	}

	public void startDocument() {
		accumulator = new StringBuffer();
		captcha = new Captcha();
	}

	public void characters(char[] buffer, int start, int length) {

		accumulator.append(buffer, start, length);
	}

	public void startElement(String namespaceURL, String localName, String qname, Attributes attributes) {
		accumulator.setLength(0);
	}
}
